package com.xiyuan.smartutils.template.engine.expression;

import com.xiyuan.smartutils.Classes;
import com.xiyuan.smartutils.constants.CodeConstants;
import com.xiyuan.smartutils.template.engine.VariableMap;
import com.xiyuan.smartutils.template.engine.exception.ExpressionException;
import com.xiyuan.smartutils.template.engine.expression.operator.Operator;
import com.xiyuan.smartutils.template.engine.expression.primitive.Primitive;
import com.xiyuan.smartutils.template.engine.expression.symbol.Symbol;
import com.xiyuan.smartutils.template.engine.statement._Break.BreakException;
import com.xiyuan.smartutils.template.engine.statement._Continue.ContinueException;
import com.xiyuan.smartutils.template.engine.statement._RETURN.ReturnException;

import java.io.Serializable;
import java.lang.reflect.Field;

/**
 * 表达式基类<br>
 *
 * @author lgz 2020年10月26日 新建与整理
 * @see Operator 运算符表达式<br>
 * @see Primitive 对象原型表达式<br>
 */
public abstract class Expression implements CodeConstants, Serializable {
    private static final long serialVersionUID = 1L;
    private String path;
    private int line;
    private int column;
    protected Expression target;
    
    public Expression(String path, int line, int column) {
        this.path = path;
        this.line = line;
        this.column = column;
    }
    
    public String getPath() {
        return path;
    }
    
    public void setPath(String path) {
        this.path = path;
    }
    
    public int getLine() {
        return line;
    }
    
    public Expression setLine(int line) {
        this.line = line;
        return this;
    }
    
    public int getColumn() {
        return column;
    }
    
    public Expression setColumn(int column) {
        this.column = column;
        return this;
    }
    
    public Expression getTarget() {
        return target;
    }
    
    /**
     * 验证不支持的表达式
     *
     * @param prevMessage
     * @param ops
     */
    protected void assertSymbo(String prevMessage, Expression... ops) {
        if (ops == null) {return;}
        
        
        for (int i = 0; i < ops.length; i++) {
            Expression ex = ops[i];
            if (ex instanceof Symbol) {
                throw new ExpressionException(ex,
                                              (prevMessage == null
                                               ? ""
                                               : prevMessage) + "表达式{" + this + "}，格式不正确，不允许调用符号表达式{" + ex + "}");
            }
        }
    }
    
    public Expression setTarget(Expression target) {
        return setTarget(target, false);
    }
    
    /***
     * 设置 设置父级所属对象，过已经设置了父对象，则在对父对象进行设置父对象<br>
     * 如果 override == true 则只对当前进行设置父对象
     *
     * @param target 父对象
     * @param override 是否覆盖当前父对象
     * @return this instance
     */
    public Expression setTarget(Expression target, boolean override) {
        this.assertSymbo(null, target);
        if (!override && this.target != null) {this.target.setTarget(target);}
        
        this.target = target;
        return this;
    }
    
    /*** 获取对象属性值 */
    public Object getPropertyValue(Object obj, Expression clzExp, String property) throws ExpressionException {
        Field field = getField(obj, property);
        if (field != null) {return Classes.getFieldValue(obj, field);}
        
        throw new ExpressionException(this, "表达式 {" + clzExp + "}结果未找到“" + property + "”属性");
    }
    
    /*** 获取对象属性值 */
    public Field getField(Object obj, String property) throws ExpressionException {
        if (obj != null) {
            // 实例属性
            Class<?> c = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
            return Classes.getFieldDeep(c, property);
        }
        
        return null;
    }
    
    /**
     * 提供公开的执行表达式函数
     */
    public Object execute(VariableMap variableMap) {
        try {
            return this.build(variableMap);
        }
        catch (Throwable e) {
            // 表达式异常
            // ContinueException 继续循环
            // BreakException 退出循环
            // ReturnException 返回
            if (e instanceof ExpressionException || e instanceof ContinueException || e instanceof BreakException || e instanceof ReturnException) {
                throw e;
            }
            
            throw new ExpressionException(this, "表达式{ " + this + " }调用异常 " + e.getMessage(), e);
        }
    }
    
    /**
     * 强制子类实现toString方法
     *
     * @return 表达式原型字符串
     */
    @Override
    public abstract String toString();
    
    /**
     * 强制子类提供表达式类型，方便switch
     *
     * @return 表达式int类型
     */
    public abstract int getType();
    
    /**
     * 子类必须实现，执行表达式生成结果值
     *
     * @param attrMap 变量表
     * @return 结果值
     * @throws ExpressionException 可能的表达式异常
     */
    protected abstract Object build(VariableMap attrMap);
    
}
